﻿using System;
using System.Speech.Recognition;
using System.Speech.Synthesis;
using System.Threading;
using System.Linq;
using System.Runtime.InteropServices;
using System.Globalization;
using System.Media;
using System.IO;
using System.Security.Principal;
using Microsoft.Win32;
using System.Threading.Tasks;

namespace DigiMate
{
	public class DigiMate
	{
		static bool completed;
		public SpeechRecognitionEngine recognizer = new SpeechRecognitionEngine(new CultureInfo("en-US"));
		private System.Threading.Timer watchdog;
		public static volatile int dldnow;


		WeatherService ws = new WeatherService();
		NewsService ns = new NewsService();
		SleepService ss = new SleepService();
		CurrencyService currs = new CurrencyService();
		TranslateService trs = new TranslateService();

		private void OnPowerChange(object s, PowerModeChangedEventArgs e) 
		{
			switch ( e.Mode ) 
			{
				case PowerModes.Resume:
					Speaker.Speak("Привет " + Environment.UserName + ", я готова к работе");
					break;
				case PowerModes.Suspend:
				break;
			}
		}


		private static Object lockObj = new Object();
		private static bool anyServiceActive = false;

		public static bool AnyServiceActive
		{
			get
			{
				lock (lockObj)
				{
					return anyServiceActive;
				}
			}
			set
			{
				lock (lockObj)
				{
					anyServiceActive = value;

					//if (!anyServiceActive)
					//{
					//	try
					//	{
					//		DigiMate.Instance.recognizer.RecognizeAsync(RecognizeMode.Multiple);
					//	}
					//	catch
					//	{ }
					//}
				}
			}
		}
		

		private static DigiMate InstanceValue;

		public static DigiMate Instance
		{
			get 
			{
				if (InstanceValue == null)
				{
					lock (typeof(DigiMate))
					{
						if (InstanceValue == null)
						{
							InstanceValue = new DigiMate();
						}
					}	   
				}

				return InstanceValue;
			}
		}

		public void watchdog_elapsed(object obj)
		{
			return;

			lock (lockObj)
			{
				if (!anyServiceActive)
				{
					try
					{
						Console.WriteLine("Watchdog starting recognizer");
						DigiMate.Instance.recognizer.RecognizeAsync(RecognizeMode.Multiple);
					}
					catch
					{
						//Console.WriteLine("Watchdog Failed to restart recognizer");
					}
				}
			}
		}

		public DigiMate()
		{
			watchdog = new System.Threading.Timer(new TimerCallback(watchdog_elapsed), dldnow, 1000 * 1, 1000 * 10);
			SystemEvents.PowerModeChanged += OnPowerChange;



			// Create an in-process speech recognizer.


			// Create a grammar for choosing cities for a flight.
			Choices cities = new Choices(new string[] { "off", "on" });

			GrammarBuilder lightGrammar = new GrammarBuilder("Computer");
			lightGrammar.Culture = recognizer.RecognizerInfo.Culture;
			lightGrammar.Append("light");
			lightGrammar.Append(cities);

			GrammarBuilder helloGrammar = new GrammarBuilder("Prevet");
			helloGrammar.Culture = recognizer.RecognizerInfo.Culture;

			GrammarBuilder pogodaGrammar = new GrammarBuilder("Prognoz Pogodi");
			pogodaGrammar.Culture = recognizer.RecognizerInfo.Culture;

			GrammarBuilder probkiGrammar = new GrammarBuilder("Probki");
			probkiGrammar.Culture = recognizer.RecognizerInfo.Culture;

			GrammarBuilder newsGrammar = new GrammarBuilder("Computer Novosti");
			newsGrammar.Culture = recognizer.RecognizerInfo.Culture;

			GrammarBuilder translateGrammar = new GrammarBuilder("Computer translate");
			translateGrammar.Culture = recognizer.RecognizerInfo.Culture;

			GrammarBuilder sleepGrammar = new GrammarBuilder("Computer vikluchaisya");
			sleepGrammar.Culture = recognizer.RecognizerInfo.Culture;

			GrammarBuilder currencyGrammar = new GrammarBuilder("Computer kakoy kurs rublya");
			currencyGrammar.Culture = recognizer.RecognizerInfo.Culture;

			Choices initialChioces = new Choices(new GrammarBuilder[] { lightGrammar, helloGrammar, pogodaGrammar, probkiGrammar, newsGrammar, translateGrammar, sleepGrammar, currencyGrammar });

			// Construct a Grammar object and load it to the recognizer.
			GrammarBuilder gb = new GrammarBuilder(initialChioces);
			gb.Culture = recognizer.RecognizerInfo.Culture;

			Grammar lightManager = new Grammar(gb);
			lightManager.Name = ("Grammar");
			recognizer.LoadGrammarAsync(lightManager);



			// Attach event handlers.
			recognizer.SpeechDetected +=
				new EventHandler<SpeechDetectedEventArgs>(
				SpeechDetectedHandler);
			recognizer.SpeechHypothesized +=
				new EventHandler<SpeechHypothesizedEventArgs>(
				SpeechHypothesizedHandler);
			recognizer.SpeechRecognitionRejected +=
				new EventHandler<SpeechRecognitionRejectedEventArgs>(
				SpeechRecognitionRejectedHandler);
			recognizer.SpeechRecognized +=
				new EventHandler<SpeechRecognizedEventArgs>(
				SpeechRecognizedHandler);
			recognizer.RecognizeCompleted +=
				new EventHandler<RecognizeCompletedEventArgs>(
				RecognizeCompletedHandler);

			// Assign input to the recognizer and start asynchronous
			// recognition.
			recognizer.SetInputToDefaultAudioDevice();
			recognizer.BabbleTimeout = TimeSpan.FromSeconds(1);


			Speaker.Speak("Я готова к работе Повелитель");

			completed = false;
			Console.WriteLine("Starting asynchronous recognition...");
			recognizer.RecognizeAsync(RecognizeMode.Multiple);

			
			Console.WriteLine("DigiMate instance created");
		}


		// Handle the SpeechDetected event.
		public void SpeechDetectedHandler(object sender, SpeechDetectedEventArgs e)
		{
			Console.WriteLine(" In SpeechDetectedHandler:");
			Console.WriteLine(" - AudioPosition = {0}", e.AudioPosition);
		}

		// Handle the SpeechHypothesized event.
		public void SpeechHypothesizedHandler(
		  object sender, SpeechHypothesizedEventArgs e)
		{
			Console.WriteLine(" In SpeechHypothesizedHandler:");

			string grammarName = "<not available>";
			string resultText = "<not available>";
			if (e.Result != null)
			{
				if (e.Result.Grammar != null)
				{
					grammarName = e.Result.Grammar.Name;
				}
				resultText = e.Result.Text;
			}

			Console.WriteLine(" - Grammar Name = {0}; Result Text = {1}",
			  grammarName, resultText);
		}


		public void SpeechRecognitionRejectedHandler(
		  object sender, SpeechRecognitionRejectedEventArgs e)
		{
			if (DigiMate.AnyServiceActive)
				return;

			recognizer.RecognizeAsyncCancel();

			try
			{
				Console.WriteLine(" In SpeechRecognitionRejectedHandler:");

				string grammarName = "<not available>";
				string resultText = "<not available>";
				if (e.Result != null)
				{
					if (e.Result.Grammar != null)
					{
						grammarName = e.Result.Grammar.Name;
					}
					resultText = e.Result.Text;
				}

				Console.WriteLine(" - Grammar Name = {0}; Result Text = {1}",
				  grammarName, resultText);

				Speaker.Speak("Я не поняла. Повторите...");

				if (false)
				{
					FileInfo fi = new FileInfo(Path.GetTempFileName());
					if (!fi.Directory.Exists)
					{
						fi.Directory.Create();
					}

					FileStream stream = new FileStream(fi.FullName, FileMode.Create);
					e.Result.Audio.WriteToWaveStream(stream);
					stream.Close();

					// Greet the person using the saved audio.
					SpeechSynthesizer synthesizer = new SpeechSynthesizer();
					PromptBuilder builder = new PromptBuilder();
					builder.AppendText("Вы сказали");
					builder.AppendAudio(fi.FullName);
					synthesizer.Speak(builder);
				}
			}
			finally
			{
				if (!DigiMate.AnyServiceActive)
					recognizer.RecognizeAsync(RecognizeMode.Multiple);
			}
		}


		public async void SpeechRecognizedHandler(
		  object sender, SpeechRecognizedEventArgs e)
		{
			Console.WriteLine(" In SpeechRecognizedHandler.");

			if (DigiMate.AnyServiceActive)
				return;

			try
			{
					
				recognizer.RecognizeAsyncCancel();

				string grammarName = "<not available>";
				string resultText = "<not available>";
				
				if (e.Result != null)
				{
					Action a = null;
					if (e.Result.Grammar != null)
					{
						grammarName = e.Result.Grammar.Name;
					}
					resultText = e.Result.Text;

					switch (resultText.ToLower())
					{
						case "computer light off":
						case "computer light on":
							if (e.Result.Words[2].Text.ToLower() == "off")
							{
								Speaker.Speak("хорошо. Выключаю свет");
							}
							else if (e.Result.Words[2].Text.ToLower() == "on")
							{
								Speaker.Speak("хорошо. Включаю свет");
							}
							break;

						case "prevet":
							Speaker.Speak("Привет " + Environment.UserName);
							break;

						case "prognoz pogodi":
							a = new Action(delegate { ws.RunService(resultText);});
							break;

						case "computer novosti":
							a = new Action(delegate { ns.RunService(resultText);});
							break;

						case "computer vikluchaisya":
							a = new Action(delegate { ss.RunService(resultText);});
							break;

						case "computer kakoy kurs rublya":
							a = new Action(delegate { currs.RunService(resultText);});
							break;

						case "computer translate":
							a = new Action(delegate { trs.RunService(resultText); });
							break;
					}
				
					if (a != null)
					{
						await Task.Run(a);
					}

				}

				
				Console.WriteLine(" - Grammar Name = {0}; Result Text = {1}",
				  grammarName, resultText);

				//await Task.Run(a);

			}
			finally
			{
				try
				{
					recognizer.RecognizeAsync(RecognizeMode.Multiple);
				}
				catch
				{
					Console.WriteLine("RecognizeAsync call error");
				}
			}
		}

		// Handle the RecognizeCompleted event.
		public void RecognizeCompletedHandler(
		  object sender, RecognizeCompletedEventArgs e)
		{
			Console.WriteLine(" In RecognizeCompletedHandler.");

			if (e.Error != null)
			{
				Console.WriteLine(
				  " - Error occurred during recognition: {0}", e.Error);
				return;
			}
			if (e.InitialSilenceTimeout || e.BabbleTimeout)
			{
				Console.WriteLine(
				  " - BabbleTimeout = {0}; InitialSilenceTimeout = {1}",
				  e.BabbleTimeout, e.InitialSilenceTimeout);
				return;
			}
			if (e.InputStreamEnded)
			{
				Console.WriteLine(
				  " - AudioPosition = {0}; InputStreamEnded = {1}",
				  e.AudioPosition, e.InputStreamEnded);
			}
			if (e.Result != null)
			{
				Console.WriteLine(
				  " - Grammar = {0}; Text = {1}; Confidence = {2}",
				  e.Result.Grammar.Name, e.Result.Text, e.Result.Confidence);
				Console.WriteLine(" - AudioPosition = {0}", e.AudioPosition);
			}
			else
			{
				Console.WriteLine(" - No result.");
			}

			completed = true;
		}


	}
}
